// 装饰器

// 1.装饰器的基本使用
const moveDecorator: ClassDecorator = (target: Function) => {
  // 拓展类方法
  target.prototype.getPosition = function (): Object {
    console.log('getPosition' + { x: 12, y: 56 });
    return { x: 12, y: 56 };
  }
};

@moveDecorator
class Tank {
  // getPosition() {}
 };

let tank1 = new Tank();

(tank1 as any).getPosition();
(<any>tank1).getPosition();




// 2.使用装饰器统一增加方法（代替类的继承方式）
let messageDecorator: ClassDecorator = (target: Function) => {
  // 增加message方法
  target.prototype.message = (val: string) => {
    console.log('发布信息：' + val);
  }
};
@messageDecorator
class Player {
  login() {
    console.log('欢迎你---player');
    (this as any).message('message1');
  }
}
(new Player).login();

@messageDecorator
class Test {
  login() {
    console.log('欢迎你---Test');
    (<any>this).message('message---test');
  }
};
(new Test).login();


// 3.类装饰器工厂
let musicDecoratorFactory = function (type: string): ClassDecorator {
  switch (type) {
    case 'tank':
      return (target: Function) => {
        target.prototype.palyMusic = function () {
          console.log('播放战争音乐');
        }
      };
      break;
    default:
      return (target: Function) => {
        target.prototype.palyMusic = function () {
          console.log('播放欢快的音乐');
        }
      };
      break;
  }
}
@musicDecoratorFactory('tank')
class Tank2 {

};
@musicDecoratorFactory('player')
class Player2 {

}
((new Tank2) as any).palyMusic();
(<any>(new Player2)).palyMusic();


// 4.方法装饰器
const FnDecorator: MethodDecorator = (target: object, propertyKey: symbol | string, descriptor: PropertyDescriptor) => {
  const method = descriptor.value;
  descriptor.value = function () {
    console.log('hello word---change');
  }
}
class TestPro {
  @FnDecorator
  public show(str: string): string {
    return 'hello world';
  }
}
(new TestPro).show('test');

// 实现代码高亮
const methodDecorator: MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
  const method = descriptor.value;
  console.log(JSON.stringify(descriptor.value));
  descriptor.value = () => {
    return `<div style="color:red;">${method()}</div>`
  };
}
class HeightColor {
  @methodDecorator
  showTxt(str: string): string {
    // return str;
    return 'cnsdsdb';
  }
};

let txt = (new HeightColor).showTxt('黑来咯biddy');
console.log(txt);


// 5.通过函数在装饰器工厂实现延时
const delayFn = (time?: number): MethodDecorator => {
  return (target: object, proprertyKey: string | symbol, descripter: PropertyDescriptor) => {
    let method = descripter.value;
    descripter.value = () => {
      setTimeout(function () { 
        method();
      }, time || 500);
    }
  }

}
class DelayTime {
  @delayFn()
  runing() {
    console.log('延时后执行');
  }
}

let instance1 = new DelayTime();
instance1.runing();

//  6.通过装饰器实现一个自定义错误打印

const ErrorDecorator= (title: string = '自定义错误文案', fontSize: number = 14): MethodDecorator => {
  return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    let method = descriptor.value;
    descriptor.value = () => {
      try {
        method()
       } catch (err: any) {
         console.log(`%c${err}-${title}`, `color: red;font-size:${fontSize}px`)
      }
    }
  }
}

class ErrorTest {
  @ErrorDecorator()
  getErr() {
    throw Error('您查找的用户不存在');
  }
}


// 7.属性装饰器
const propertyDecoratorFn: PropertyDecorator = (target: object, propertyKey: string | symbol) => {
  Object.defineProperty(target, propertyKey, {
    get() {
      console.log('get----' , propertyKey);
    },
    set(val) {
      console.log('set----' , propertyKey, val);
    }
    })
}

// const propertyDecoratorFn: PropertyDecorator = (...ags: any[]) => {
//   console.log(ags);
// }
class PropertyCls {
  @propertyDecoratorFn
  public name: string | undefined;
}
let instance4 = new PropertyCls;
instance4.name = 'zhoumingle';
instance4.name;




// 8.参数装饰器
const parameDecoratorFn: ParameterDecorator= (target: object, propertyKey: string | symbol, parameterIndex: number) => {
  console.log('参数装饰器:', target, propertyKey, parameterIndex);
}

class ParameCls {
  get(@parameDecoratorFn name: string): void {
    console.log('hello word-----!!!');
  }
}

let instance2 = new ParameCls;
instance2.get('123');